import Vue from 'vue'
import axios from 'axios'
import qs from 'qs'
import VueAxios from '../utils/axios'
import {
  apiBaseURL,
  reqTimeout,
  accessToken,
  headerToken,
  cancelRequest
} from '../env'

function toType (obj) {
  return {}.toString.call(obj).match(/\s([a-z])+/i)[1].toLowerCase()
}

// 实例缓存
let instants = []

/**
 * 处理服务器错误及接口错误(非200状态码)
 * @param {object} error - 错误信息
 */
const handleError = (error) => {
  // 处理服务器错误
  if (toType(error) === 'error') {
    return null
  }

  // 处理非200状态码
  switch (error.code) {
    case 401: {
    }
  }

  return Promise.reject(error)
}

/**
 * axios实例增强
 * 可指定发送json或formdata
 * @param {any}} instance
 */
const enhance = instance => {
  const methods = ['post', 'put', 'get', 'delete', 'patch']
  methods.forEach(method => {
    const originalMethod = instance[method]
    const isGet = method === 'get'
    const isDelete = method === 'delete'
    instance[method] = function (url, data, isJson = true) {
      const config = {
        headers:
          !isJson
            ? { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' }
            : {}
      }

      data = (!isJson && !isDelete) ? qs.stringify(data) : data

      return originalMethod.call(
        instance,
        url,
        isGet
          ? { params: data }
          : (isDelete
            ? (isJson ? { data }
              : { params: data })
            : data),
        config
      )
    }
  })
}

const intercept = service => {
  service.interceptors.request.use(config => {
    let token = Vue.ls.get(accessToken)
    if (token) {
      config.headers[headerToken] = token
    }
    if (cancelRequest) {
      config.cancelToken = new axios.CancelToken(cancel => {
        window.reqManager && window.reqManager.add(cancel)
      })
    }
    return config
  }, handleError)

  service.interceptors.response.use(response => {
    const { data = {} } = response
    if (
      (data.result && data.result !== httpStatus.OK)) {
      return handleError(data)
    }
    return data
  }, handleError)
}

const serviceFactory = (baseURL = apiBaseURL) => {
  let instance = instants.find(service => service.id === baseURL)
  if (instance) return instance.service

  instance = axios.create({
    baseURL: baseURL,
    timeout: reqTimeout
  })

  instants.push({
    id: baseURL,
    service: instance
  })

  intercept(instance)

  enhance(instance)

  return instance
}

const service = serviceFactory()

const Axios = {
  install (Vue) {
    Vue.use(VueAxios, service)
  }
}

export default Axios

export { service as axios, serviceFactory as createAxios }
